package servidor;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import juego.comando;
import juego.juegoprotocol;
import juego.metodos;
import cliente.jugador;
import juego.ValidadorBoggle;

//clase servermetodos contiene los metodos que ejecutan la lectura, decodificacion y escritura de las operaciones del juego
public class servermetodos {
	
	private String strComando;
	private ObjectInputStream inobj;	
	private ObjectOutputStream outobj;	
	private comando cmdbruto;
	
	
	public servermetodos(ObjectInputStream inobj, ObjectOutputStream outobj/*, boolean dormirhilo*/){
		this.inobj = inobj;
		this.outobj = outobj;
		this.strComando = "";	
		this.setCmdbruto(null);
	}
	
	//Decodifica el comando enviado por el socket, el tipo de operacion a ejecutar y los objetos que trae
	public Object leerComando() throws IOException {   
		Object  objeto = null;  
		comando cmd    = null;

		try {			
			cmd        = (comando) inobj.readObject();
			setCmdbruto(cmd);
			objeto     = cmd.getObjeto();	
			strComando = cmd.getComando();
		} catch (ClassNotFoundException e) {
			System.out.println("ERROR");
			e.printStackTrace();
		}    	

		return objeto;
	}
	    
	public String GetComando(){
		return strComando;
	}
	
	//procesa el comando proveniente de los clientes    
	@SuppressWarnings("unchecked")
	public synchronized comando procesarComando(Object objeto, Object objetoaux) throws InterruptedException {        

		comando respuesta = new comando(null, null, null, 0);
		int indx = -1;

		//Conexion de cliente servidor    	
		if(strComando.equalsIgnoreCase(juegoprotocol.OP_CONEXION)){
			int ident = (Integer) objetoaux;        	
			if(ident <= serverboggle.nrojugadores){
				for(int i=0;i<=serverboggle.jugadores.size()-1;i++) 					
					if(serverboggle.jugadores.get(i).getIdentificador() == ident){
						serverboggle.jugadores.get(i).setIdentificador(ident);
						serverboggle.jugadores.get(i).setNombre(((jugador)objeto).getNombre());
						respuesta.setComando(juegoprotocol.CONEXION_EST);
						respuesta.setExtrai(ident);
						respuesta.setObjeto(serverboggle.opcserver);											
						break;
					}
			} else respuesta.setComando(juegoprotocol.MAX_JUGADORES);	
		}
		//Peticion de inicio de rodas o juego y envio de tablero   	
		else if(strComando.equalsIgnoreCase(juegoprotocol.OP_TABLERO)){
			
			indx = getIndxLista((Integer) objetoaux);
			if((Integer)objeto == 0){
				serverboggle.jugadores.get(indx).setRonda(serverboggle.jugadores.get(indx).getRonda()+1);						
			}
			
			
			//se verifica que todos los clientes hayan pedido el inicio de la ronda y del tablero
			//si uno o varios no han pedido el tablero se duermen las peticiones hasta que el ultimo 
			//cliente pida y despierte todos los hilos y se inicien de forma sincronizada la rodan de todos
			//los clientes
			for(int i=0;i<=serverboggle.jugadores.size()-1;i++)
				if(serverboggle.jugadores.get(i).getRonda() < serverboggle.jugadores.get(indx).getRonda()){
					serverboggle.dormirhilo = true;	
					break;
				}else if(i==serverboggle.jugadores.size()-1){
					
					//se genera el tablero para los jugadores
					serverboggle.tablero = metodos.generartablero();					
					serverboggle.dormirhilo = false;
				}
			
			respuesta.setComando(juegoprotocol.OP_GO);	
			respuesta.setExtrai(serverboggle.jugadores.get(indx).getRonda());
				
		}
		//Recepcion de resultados derondas y calculo de puntajes, los hilos se dormiran hasta que todos los 
		//jugadores hayan registrados tus palabras y asi poder hacer el calculo del puntaje en general
		else if(strComando.equalsIgnoreCase(juegoprotocol.OP_POSICIONES)){
			
			indx = getIndxLista((Integer) objetoaux);
			serverboggle.jugadores.get(indx).setListapalabras((ArrayList<String>) objeto);
			for(int i=0;i<=serverboggle.jugadores.size()-1;i++)
				if(serverboggle.jugadores.get(i).getListapalabras() == null){
					serverboggle.dormirhilo2 = true;
					break;
				}
				else if(i==serverboggle.jugadores.size()-1){
					elimpalabras(indx);
					serverboggle.dormirhilo2 = false;
				}
					
			
			//si no estan todas la lista de palabras registradas se procede a dormir el hilo por 2 seg. 
			while(serverboggle.dormirhilo2)
				wait(2000);
			
			//calculo de puntaje
			int pts = calcularpts(indx); 
			serverboggle.jugadores.get(indx).setPuntaje(pts);
			serverboggle.jugadores.get(indx).setPuntajeacum(serverboggle.jugadores.get(indx).getPuntajeacum()+pts);
			respuesta.setComando(juegoprotocol.OP_POSICIONES);
			respuesta.setExtrai(pts);
			respuesta.setExtras(Integer.toString(serverboggle.jugadores.get(indx).getPuntajeacum()));
		}
		//Se calcula el jugador ganador y se crean las posiciones de cada jugador de mayor puntaje a menor
		else if(strComando.equalsIgnoreCase(juegoprotocol.OP_POSICIONESF)){
			respuesta.setComando(juegoprotocol.OP_POSICIONESF);	
			respuesta.setObjeto(serverboggle.jugadores);
		}

		return respuesta;
	}
	
	//metodo que escribe la respuesta el cliente
	public synchronized  void escribirRespuesta(comando respuesta) throws IOException {


		
		//si la variable dormirhilo es true se procede a parar el hilo por un tiempo esperado 
		//otras conexiones o respuestas de clientes para operaciones sincroinzadas como el in-
		//icio de rodas...
		try {
			if(serverboggle.dormirhilo && cmdbruto.getComando().equalsIgnoreCase(juegoprotocol.OP_TABLERO)){
				while(serverboggle.dormirhilo)
					wait(2000);
			}
			
			//cancela la varibale dormirhilo
			serverboggle.dormirhilo = false;			
			
			//se incializan las lista de los jugadores para las siguientes rondas
			if(cmdbruto.getComando().equalsIgnoreCase(juegoprotocol.OP_TABLERO))
				serverboggle.jugadores.get(getIndxLista(cmdbruto.getExtrai())).setListapalabras(null);
							
		} catch (InterruptedException e) {				
			e.printStackTrace();
		}
		
		//se le responde al cliente
		if(cmdbruto.getComando().equalsIgnoreCase(juegoprotocol.OP_TABLERO))
			respuesta.setObjeto(serverboggle.tablero);
		
		//se envia la respuesta a los clientes
		outobj.writeObject(respuesta);

	}
	
	//metodo que calcula y devuelve el puntaje 
	private void elimpalabras(int indx){
		
		String palabra = "";
		
		//fase 1, eliminar las palabras que tengan en comun los jugadores
		for(int i=0;i<=serverboggle.jugadores.size()-1;i++)
			for(int y=0;y<=serverboggle.jugadores.get(i).getListapalabras().size()-1;y++){
				palabra = serverboggle.jugadores.get(i).getListapalabras().get(y);
				for(int x=0;x<serverboggle.jugadores.size()-1;x++)
					if(x!=i && serverboggle.jugadores.get(x).getListapalabras().contains(palabra))
						serverboggle.jugadores.get(x).getListapalabras().remove(palabra);
			}
	}
	
	//elimina palabras en listas
	private int calcularpts(int indx){
		int pts = 0; 
		String  palabra = "";
		ValidadorBoggle validar = new ValidadorBoggle();
		for(int i=0;i<=serverboggle.jugadores.get(indx).getListapalabras().size()-1;i++){
			palabra = serverboggle.jugadores.get(indx).getListapalabras().get(i);
			if(!palabra.equalsIgnoreCase("") && serverboggle.listadepalabras.contains(palabra.toLowerCase()))
				if(validar.validar(serverboggle.tablero,palabra))
					switch (palabra.length()) {
					case 3:
					case 4: pts +=1;	
					break;
					case 5: pts +=2;
					break;
					case 6: pts +=3;
					break;
					case 7: pts +=5;
					break;
					case 8:					
					default:  pts +=11;					
					break;
					}
		}
		
		
		return pts;
	}
	
	//metodo set de comando
	public void setCmdbruto(comando cmdbruto) {
		this.cmdbruto = cmdbruto;
	}
	
	//metodo que devuelve un comando en bruto
	public comando getCmdbruto() {
		return cmdbruto;
	}
	
	//metodo que devuelve el index dado un indentificador de un cliente
	private int getIndxLista(int ident){
		
		for(int i=0;i<=serverboggle.jugadores.size()-1;i++)
			if(serverboggle.jugadores.get(i).getIdentificador() == ident)
				return i;
				
		return -1;
	}

}
